/*	Copyright (c) 2016 Jean-Marc VIGLINO, 
  released under the CeCILL-B license (French BSD license)
  (http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol_ext_inherits from '../util/ext'
import {unByKey as ol_Observable_unByKey} from 'ol/Observable'
import ol_interaction_CenterTouch from './CenterTouch'
import ol_style_Style from 'ol/style/Style'
import ol_style_Circle from 'ol/style/Circle'
import ol_style_Stroke from 'ol/style/Stroke'
import ol_style_Fill from 'ol/style/Fill'
import ol_Feature from 'ol/Feature'
import ol_layer_Vector from 'ol/layer/Vector'
import ol_source_Vector from 'ol/source/Vector'
import ol_geom_LineString from 'ol/geom/LineString'
import ol_geom_Polygon from 'ol/geom/Polygon'
import ol_geom_Point from 'ol/geom/Point'
import ol_geom_Circle from 'ol/geom/Circle'
import ol_ext_getMapCanvas from '../util/getMapCanvas'
import {ol_coordinate_dist2d} from '../geom/GeomUtils'

/** Interaction DrawTouch :
 * @constructor
 * @fires drawstart
 * @fires drawend
 * @extends {ol_interaction_CenterTouch}
 * @param {olx.interaction.DrawOptions} options
 *  @param {ol_source_Vector | undefined} options.source Destination source for the drawn features.
 *  @param {ol.geom.GeometryType} options.type Drawing type ('Point', 'LineString', 'Polygon') not ('MultiPoint', 'MultiLineString', 'MultiPolygon' or 'Circle'). Required.
 *	@param {boolean} options.tap enable on tap, default true
 *  @param {ol_style_Style|Array<ol_style_Style>} options.targetStyle a style to draw the target point, default cross style
 *  @param {string} options.composite composite operation : difference|multiply|xor|screen|overlay|darken|lighter|lighten|...
 */
var ol_interaction_DrawTouch = function(options) {
  options = options||{};

  options.handleEvent = function(e) {
    if (this.get('tap')) {
      switch (e.type) {
        case 'singleclick': {
          this.addPoint();
          break;
        }
        case 'dblclick': {
          this.addPoint();
          this.finishDrawing();
          return false;
          //break;
        }
        default: break;
      }
    }
    return true;
  }
  ol_interaction_CenterTouch.call(this, options);

  this.typeGeom_ = options.type;
  this._geometryFunction = options.geometryFunction;
  this.source_ = options.source;
  this.set('tap', (options.tap!==false));

  // Style
  var white = [255, 255, 255, 1];
  var blue = [0, 153, 255, 1];
  var width = 3;
  var defaultStyle = [
    new ol_style_Style({
      stroke: new ol_style_Stroke({ color: white, width: width + 2 })
    }),
    new ol_style_Style({
      image: new ol_style_Circle({
        radius: width * 2,
        fill: new ol_style_Fill({ color: blue }),
        stroke: new ol_style_Stroke({ color: white, width: width / 2 })
      }),
      stroke: new ol_style_Stroke({ color: blue, width: width }),
      fill: new ol_style_Fill({
        color: [255, 255, 255, 0.5]
      })
    })
  ];

  this.overlay_ = new ol_layer_Vector({
    source: new ol_source_Vector({useSpatialIndex: false }),
    style: defaultStyle
  });

  this.geom_ = [];
  
};
ol_ext_inherits(ol_interaction_DrawTouch, ol_interaction_CenterTouch);

/**
 * Remove the interaction from its current map, if any,  and attach it to a new
 * map, if any. Pass `null` to just remove the interaction from the current map.
 * @param {ol.Map} map Map.
 * @api stable
 */
ol_interaction_DrawTouch.prototype.setMap = function(map) {
  if (this._listener.drawSketch) ol_Observable_unByKey(this._listener.drawSketch);
  this._listener.drawSketch = null;

  ol_interaction_CenterTouch.prototype.setMap.call (this, map);
  this.overlay_.setMap(map);

  if (this.getMap()){
    this._listener.drawSketch = this.getMap().on('postcompose', this.drawSketchLink_.bind(this));
  }
};

/** Get geometry type
 * @return {ol.geom.GeometryType}
 */
ol_interaction_DrawTouch.prototype.getGeometryType = function() {
  return this.typeGeom_;
};

/** Start drawing and add the sketch feature to the target layer. 
 * The ol.interaction.Draw.EventType.DRAWEND event is dispatched before inserting the feature.
 */
ol_interaction_DrawTouch.prototype.finishDrawing = function() {
  if (!this.getMap()) return;

  var valid = true;
  if (this._feature) {
    switch (this.typeGeom_) {
      case 'LineString': {
        if (this.geom_.length > 1) {
          this._feature.setGeometry(new ol_geom_LineString(this.geom_));
        } else {
          valid = false;
        }
        break;
      }
      case 'Polygon': {
        // Close polygon
        if (this.geom_[this.geom_.length-1] != this.geom_[0]) {
          this.geom_.push(this.geom_[0]);
        }
        // Valid ?
        if (this.geom_.length > 3) {
          this._feature.setGeometry(new ol_geom_Polygon([ this.geom_ ]));
        } else {
          valid = false;
        }
        break;
      }
      default: break;
    }
    if (this._feature) this.source_.addFeature (this._feature);
    this.dispatchEvent({ 
      type: 'drawend',
      feature: this._feature,
      valid: valid
    });
  }  

  // reset
  this.geom_ = [];
  this.drawSketch_();
  this._feature = null;
};

/** Add a new Point to the drawing
 */
ol_interaction_DrawTouch.prototype.addPoint = function() {
  if (!this.getMap()) return;

  this.geom_.push(this.getPosition());

  var start = false;
  if (!this._feature) {
    this._feature = new ol_Feature();
    start = true;
  }

  switch (this.typeGeom_) {
    case 'Point': 
      this._feature.setGeometry(new ol_geom_Point(this.geom_.pop()));
      break;
    case 'LineString':
    case 'Polygon':
    case 'Circle':
      this.drawSketch_();
      break;
    default: break;
  }
  // Dispatch events
  if (start) {
    this.dispatchEvent({ 
      type: 'drawstart',
      feature: this._feature
    });
  }
  if (this.typeGeom_ ==='Point'
  || (this.typeGeom_==='Circle' && this.geom_.length>1) ) {
    this.finishDrawing();
  }
};

/** Remove last point of the feature currently being drawn.
 */
ol_interaction_DrawTouch.prototype.removeLastPoint = function() {
  if (!this.getMap()) return;
  this.geom_.pop();
  this.drawSketch_();
};

/** Draw sketch
 * @private
 */
ol_interaction_DrawTouch.prototype.drawSketch_ = function() {
  if (!this.overlay_) return;
  this.overlay_.getSource().clear();
  if (this.geom_.length) {
    var geom = new ol_geom_LineString(this.geom_);
    switch (this.typeGeom_) {
      case 'Circle': {
        if (!this._feature.getGeometry()) {
          this._feature.setGeometry(new ol_geom_Circle(this.geom_[0], ol_coordinate_dist2d(this.geom_[0], this.geom_[this.geom_.length-1])));
        } else {
          this._feature.getGeometry().setCenter(this.geom_[0]);
          this._feature.getGeometry().setRadius(ol_coordinate_dist2d(this.geom_[0], this.geom_[this.geom_.length-1]));
        }
        break;
      }
      case 'Polygon': {
        if (!this._feature.getGeometry()) {
          this._feature.setGeometry(new ol_geom_Polygon([this.geom_]));
        } else {
          this._feature.getGeometry().setCoordinates([this.geom_]);
        }
        this.overlay_.getSource().addFeature(new ol_Feature(geom));
        break;
      }
      default: {
        if (!this._feature.getGeometry()) {
          this._feature.setGeometry(new ol_geom_LineString(this.geom_));
        } else {
          this._feature.getGeometry().setCoordinates(this.geom_);
        }
        break;
      }
    }
    this.overlay_.getSource().addFeature(this._feature);
    var f = new ol_Feature( new ol_geom_Point (this.geom_.slice(-1).pop()) );
    this.overlay_.getSource().addFeature(f);
  }
};

/** Draw contruction lines on postcompose
 * @private
 */
ol_interaction_DrawTouch.prototype.drawSketchLink_ = function(e) {
  if (!this.getActive() || !this.getPosition()) return;

  var ctx = e.context || ol_ext_getMapCanvas(this.getMap()).getContext('2d');
  ctx.save();
    var p, pt = this.getMap().getPixelFromCoordinate(this.getPosition());
    var ratio = e.frameState.pixelRatio || 1;
    ctx.scale(ratio,ratio);
    ctx.strokeStyle = 'rgba(0, 153, 255, 1)';
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.arc (pt[0],pt[1], 5, 0, 2*Math.PI);
    ctx.stroke();
    if (this.geom_.length) {
      if (this.typeGeom_ === 'Circle') {
        p = this.getMap().getPixelFromCoordinate(this.geom_[0]);
        var r = ol_coordinate_dist2d(pt, p);
        ctx.beginPath();
        ctx.arc (p[0],p[1], r, 0, 2*Math.PI);
        ctx.stroke();
      } else  {
        p = this.getMap().getPixelFromCoordinate(this.geom_[this.geom_.length-1]);
        ctx.beginPath();
        ctx.moveTo(p[0],p[1]);
        ctx.lineTo(pt[0],pt[1]);
        if (this.typeGeom_ == 'Polygon') {
          p = this.getMap().getPixelFromCoordinate(this.geom_[0]);
          ctx.lineTo(p[0],p[1]);
        }
        ctx.stroke();
      }
    }
  ctx.restore();
};

/**
 * Activate or deactivate the interaction.
 * @param {boolean} active Active.
 * @observable
 * @api
 */
ol_interaction_DrawTouch.prototype.setActive = function(b) {
  ol_interaction_CenterTouch.prototype.setActive.call (this, b);

  if (!b) this.geom_ = [];
  this.drawSketch_();
};

export default ol_interaction_DrawTouch
